using System.Collections.Generic;

namespace InfiniTec.Data
{
    /// <summary>
    /// Represents a single-valued property
    /// </summary>
    /// <typeparam name="T">The type of the property</typeparam>
    public class Property<T> : Property, IPropertyInfo
    {
        private T _Value;

        /// <summary>
        /// Gets or sets the value of the item
        /// </summary>
        public T Value
        {
            get { return _Value; }
            set
            {
                if (EqualityComparer<T>.Default.Equals(_Value, value))
                {
                    return;
                }
                _Value = value;
                SetChanged();
            }
        }

        public PropertyDefinition<T> Definition
        {
            get
            {
                return (PropertyDefinition<T>) ((IPropertyInfo) this).PropertyDefinition;
            }
        }

        /// <summary>
        /// Creates a new instance of this class using the specified namespace and local
        /// name.
        /// </summary>
        /// <param name="value">The value of the property</param>
        /// <param name="propertyDefinition">The property definition for this instance.</param>
        public Property(PropertyDefinition<T> propertyDefinition, T value)
            : base(propertyDefinition)
        {
            Value = value;
            SetChanged();
        }

        /// <summary>
        /// Creates a new instance of this class using the specified namespace and local
        /// name.
        /// </summary>
        /// <param name="propertyDefinition">The property definition for this instance.</param>
        public Property(PropertyDefinition<T> propertyDefinition): base(propertyDefinition)
        {
        }

        bool IPropertyInfo.PropertyValueIsNull
        {
            get
            {
                if (typeof(T).IsClass) return ReferenceEquals(Value, null);
                else return false;
            }
        }

        object IPropertyInfo.Value { get { return Value; } }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
        public override Property Clone()
        {
            Property<T> result;

            result = new Property<T>(Definition, Value);
            if (HasChanged)
            {
                result.SetChanged();
            }
            else
            {
                result.ResetChanged();
            }
            result.Status = Status;

            return result;
        }

        public bool Equals(Property<T> property)
        {
            if (property == null) return false;
            if (!base.Equals(property)) return false;
            return Equals(_Value, property._Value);
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(this, obj)) return true;
            return Equals(obj as Property<T>);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() + 29*(_Value != null ? _Value.GetHashCode() : 0);
        }
    }
}